type LayUI = {
  use: (deps: string[], cb: () => void) => void
}
type UseLayUI = (...deps: string[]) => Promise<any[]>


let useLayUI: UseLayUI = null
/**
 * Initialize your own useLayUI function with specified LayUI instance.
 * Singleton for an app instance.
 * @param layui 
 * @returns 
 */
export default function initUseLayUI(layui: LayUI): UseLayUI {
  if (useLayUI) {
    return useLayUI
  }
  if (!layui || typeof layui !== 'object' || typeof layui.use !== 'function') {
    throw Error('parameter layui is null')
  }

  const loaded = {}
  useLayUI = (...deps: string[]) => {
    let hasLoaded = true
    for (let i = 0; hasLoaded && i < deps.length; ++i) {
      hasLoaded = !!loaded[deps[i]]
    }
    return new Promise(resolve => {
      if (hasLoaded) {
        resolve(deps.map(dep => loaded[dep]))
      }
      else {
        // `layui.use` will swallow some module names silently, so pass a copy to it.
        layui.use([].concat(deps), function() {
          let i = 0
          const modules = deps.reduce((modules, moduleName) => {
            loaded[moduleName] = modules[i++] = this[moduleName]
            return modules
          }, [])

          resolve(modules)
        })
      }
    })
  }

  return useLayUI
}